package com.ruicar.afs.cloud.batch.dayend.process;

import cn.hutool.core.date.DateUtil;
import com.ruicar.afs.cloud.batch.dayend.vo.PenaltyInterestVO;
import com.ruicar.afs.cloud.batch.frame.AbsBatchRunner;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.uid.UidGenerator;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * @description: 逾期天数批量任务
 * @author: sijun.yu
 * @date: 2020/8/8 16:34
 */
public class OverdueDaysBatchRunner extends AbsBatchRunner {

    public static final int TOTAL_NUM = 800;
    private final UidGenerator uidGenerator = SpringContextHolder.getBean(UidGenerator.class);

    @Override
    public void process(String param){
        Connection contract = this.getConnection("contract");
        try{
            saveOrUpdatePenaltyInterest(contract);
            updateRepaymentPlanStatus(contract);
        }catch (Exception e){
            logger.error("",e);
            throw new AfsBaseException(e.getMessage());
        }finally {
            clean(contract);
        }
    }

    /**
     * 保存或更新罚息数据
     * @return
     */
    private void saveOrUpdatePenaltyInterest(Connection connection) {
        String breakPoint = loadBreakPoint();
        Long lastId = Long.parseLong(StringUtils.isEmpty(breakPoint)?"0":breakPoint);
        StringBuilder sql = new StringBuilder();
        sql.append("select plan.contract_no,plan.term_no,plan.due_date,penalty.days_amt,timestampdiff(DAY,date_format(plan.due_date,'%Y%m%d'),?) as days,main.grace_period_days,plan.receivable_rent,ifnull(plan.actual_rent,0) as actual_rent,plan.id as planId,main.contract_status,penalty.id as bpiId ")
            .append("  from basic_repayment_plan plan ")
            .append("inner join (")
            .append(" select temp.*,bpi.id from (select sum(details.amount) as days_amt,details.contract_no,details.term_no from basic_penalty_interest_details details where details.operate_type = 'newArrears' group by details.contract_no,details.term_no) as temp left join basic_penalty_interest bpi on temp.contract_no=bpi.contract_no and temp.term_no=bpi.term_no")
            .append(" ) penalty ")
            .append(" on plan.contract_no = penalty.contract_no and plan.term_no = penalty.term_no  ")
            .append(" inner join basic_main_info main on main.contract_no = plan.contract_no ")
            .append(" where plan.receivable_rent-IFNULL(plan.actual_rent,0) >0 and penalty.days_amt > 0 and plan.id>? order by plan.id asc ");
        // 保存SQL
        StringBuilder insertSql = new StringBuilder();
        insertSql.append("insert into basic_penalty_interest(id,contract_no,term_no,total_penalty,overdue_days,status,start_date,end_date,create_time,del_flag,overdue_amt,create_by) ");
        insertSql.append("values(?,?,?,?,?,?,?,?,?,?,?,?)");
        // 更新SQL
        StringBuilder updateSql = new StringBuilder();
        updateSql.append("update basic_penalty_interest set total_penalty=?, overdue_days=?, end_date=?, update_time=?, overdue_amt=? ");
        updateSql.append("where id= ?");

        PreparedStatement ps = null;
        ResultSet rs = null;
        PreparedStatement insertPs = null;
        PreparedStatement updatePs = null;
        int processCount=0;
        long lastPlanId=0L;
        Date batchDate = new Date(batchDateInfo.getBatchDate().getTime());
        String batchStringDate = batchDateInfo.getBatchStringDate();
        try {
            // 插入数据
            insertPs = connection.prepareStatement(insertSql.toString());
            // 更新数据
            updatePs = connection.prepareStatement(updateSql.toString());
            // 获取罚息数据
            ps = connection.prepareStatement(sql.toString());
            ps.setString(1,batchStringDate);
            ps.setLong(2,lastId);
            rs = ps.executeQuery();
            while(rs!=null && rs.next()){
                PenaltyInterestVO vo = new PenaltyInterestVO();
                vo.setOverdueDays(rs.getInt("days") + 1);// 还款日当天算罚息
                vo.setGracePeriodDays(rs.getInt("grace_period_days"));
                vo.setContractStatus(rs.getString("contract_status"));
                // 判断是否在宽限期内
                if(!"overdue".equals(vo.getContractStatus()) && (vo.getOverdueDays()<=vo.getGracePeriodDays() || batchDateInfo.isHoliday())){
                    continue;
                }
                vo.setContractNo(rs.getString("contract_no"));
                vo.setTermNo(rs.getInt("term_no"));
                vo.setStartDate(rs.getDate("due_date"));
                vo.setTotalPenalty(rs.getBigDecimal("days_amt"));
                vo.setReceivableRent(rs.getBigDecimal("receivable_rent"));
                vo.setActualRent(rs.getBigDecimal("actual_rent"));
                vo.setId(rs.getLong("planId"));
                vo.setEndDate(batchDate);
                BigDecimal overdueAmt = vo.getReceivableRent().add(vo.getTotalPenalty()).subtract(vo.getActualRent());
                vo.setOverdueAmt(overdueAmt);
                BigDecimal bpiId = rs.getBigDecimal("bpiId");
                if(bpiId!=null) {
                    // 更新罚息数据
                    updatePs.setBigDecimal(1, vo.getTotalPenalty());
                    updatePs.setInt(2, vo.getOverdueDays());
                    updatePs.setDate(3, vo.getEndDate());
                    updatePs.setDate(4, vo.getEndDate());// 更新时间
                    updatePs.setBigDecimal(5, vo.getOverdueAmt());
                    updatePs.setLong(6, bpiId.longValue());
                    updatePs.addBatch();
                }else {
                    insertPs.setLong(1,uidGenerator.getUID());
                    insertPs.setString(2,vo.getContractNo());
                    insertPs.setInt(3,vo.getTermNo());
                    insertPs.setBigDecimal(4,vo.getTotalPenalty());
                    insertPs.setInt(5,vo.getOverdueDays());
                    insertPs.setString(6,vo.getStatus());
                    insertPs.setDate(7,vo.getStartDate());
                    insertPs.setDate(8,vo.getEndDate());
                    insertPs.setDate(9,vo.getEndDate());// 创建时间
                    insertPs.setString(10,vo.getDelFlag());
                    insertPs.setBigDecimal(11,vo.getOverdueAmt());
                    insertPs.setString(12,"system");
                    insertPs.addBatch();
                }
                lastPlanId = vo.getId();
                processCount++;
                if(processCount%TOTAL_NUM==0){
                    insertPs.executeBatch();
                    updatePs.executeBatch();
                    connection.commit();
                    insertPs.clearBatch();
                    updatePs.clearBatch();
                    processCount=0;
                    saveBreakPoint(lastPlanId+"");
                }
            }
            if(processCount%TOTAL_NUM != 0){
                insertPs.executeBatch();
                updatePs.executeBatch();
                connection.commit();
                insertPs.clearBatch();
                updatePs.clearBatch();
                saveBreakPoint(lastPlanId+"");
            }
        }catch (Exception e){
            logger.error("",e);
            throw new AfsBaseException(e.getMessage());
        }finally {
            clean(ps);
            clean(rs);
            clean(updatePs);
            clean(insertPs);
        }
    }

    /**
     * 租金为0，更新状态为已还
     * @param connection 数据库连接
     */
    private void updateRepaymentPlanStatus(Connection connection){

        StringBuilder statusSql = new StringBuilder();
        statusSql.append("update basic_repayment_plan set status = 'REPAID' ");
        statusSql.append("where receivable_rent = 0 and due_date >= ? and  due_date<=?");

        PreparedStatement statusPs = null;
        try{
            statusPs = connection.prepareStatement(statusSql.toString());
            statusPs.setTimestamp(1, DateUtil.beginOfDay(batchDateInfo.getBatchDate()).toTimestamp());
            statusPs.setTimestamp(2, DateUtil.endOfDay(batchDateInfo.getBatchDate()).toTimestamp());
            statusPs.execute();
            connection.commit();
        }catch (Exception e){
            rollBack(connection);
            logger.error("",e);
            throw new AfsBaseException(e.getMessage());
        }finally{
            clean(statusPs);
        }
    }

}
